/**
 * @file app_midi.c
 * @brief MIDI应用层实现 - 简化版 (3阶段钢琴键打击状态机)
 * @date 2025-11-04
 */

#include "app_midi.h"
#include "drv_pwm.h"
#include "midi_protocol.h"
#include "midi_parser.h"
#include "user_config.h"
#include "board.h"
#include "sys.h"
#include "sys_manager.h"
#include <string.h>

/* 私有类型定义 -------------------------------------------------------------*/

/**
 * @brief 通道状态结构体
 */
typedef struct channel_state
{
    midi_state_e state;         /* 当前状态 */
    uint32_t timer_ms;          /* 当前阶段计时器 (ms) */
    uint32_t start_time_ms;     /* 启动时间 (用于7秒超时) */
    uint16_t velocity_16;       /* 保存的力度值 (16位, 0-65535) */
    uint16_t duty_1;            /* 第一悬停占空比 (板号特定) */
    uint16_t duty_2;            /* 第二悬停占空比 (板号特定) */
    uint32_t stage2_low_ms;     /* 阶段2低电平持续时间 (ms) */
    uint32_t stage2_high_ms;    /* 阶段2高电平持续时间 (ms) */
} channel_state_t;

/* 私有变量定义 -------------------------------------------------------------*/

channel_state_t s_channels[MIDI_CH_COUNT];  /* 8个通道状态（全局可见，便于调试）*/
static uint8_t s_board_id = 1;              /* 当前板号 (1-11) */

/* 可调参数 (通过B0 0E xx命令设置) */
static uint32_t s_time1_ms = MIDI_TIME1_DEFAULT_MS;        /* 时间1 (10-40ms) */
/* static uint32_t s_time2_base_ms = MIDI_TIME2_BASE_MS; */  /* 时间2基准 (63ms) - 暂未使用，实际使用velocity/2 */

/* 私有函数声明 -------------------------------------------------------------*/
static void process_state_machine(uint8_t ch);
static void start_stage1(uint8_t ch);
static void start_stage2_low(uint8_t ch);
static void start_stage2_high(uint8_t ch);
static void start_stage3_1(uint8_t ch);
static void start_stage3_2(uint8_t ch);
static void stop_channel(uint8_t ch);

/* 公共函数实现 -------------------------------------------------------------*/

/**
 * @brief 初始化MIDI应用层
 */
int app_midi_init(void) {
    /* 清空所有通道状态 */
    memset(s_channels, 0, sizeof(s_channels));

    for (uint8_t i = 0; i < MIDI_CH_COUNT; i++)
    {
        s_channels[i].state = MIDI_STATE_IDLE;
    }

    return 0;
}

/**
 * @brief MIDI周期性任务 (1ms调用)
 */
void app_midi_task(void) {
    /* 更新所有活跃通道的状态机 */
    for (uint8_t i = 0; i < MIDI_CH_COUNT; i++)
    {
        if (s_channels[i].state != MIDI_STATE_IDLE)
        {
            process_state_machine(i);
        }
    }
}

/**
 * @brief 音符按下 - 16位精度版本
 */
int app_midi_note_on_16(uint8_t note, uint16_t velocity_16)
{
    /* 转换MIDI音符为通道号 */
    uint8_t ch = midi_parser_note_to_channel(note, s_board_id);
    if (ch >= MIDI_CH_COUNT)
    {
        return -1; /* 不属于本板 */
    }

    /* 如果通道已激活, 先停止 */
    if (s_channels[ch].state != MIDI_STATE_IDLE)
    {
        stop_channel(ch);
    }

    /* 保存力度和板号特定占空比 */
    s_channels[ch].velocity_16 = velocity_16;
    s_channels[ch].duty_1 = drv_pwm_get_board_duty_1(s_board_id);
    s_channels[ch].duty_2 = drv_pwm_get_board_duty_2(s_board_id);
    s_channels[ch].start_time_ms = HAL_GetTick();  /* 获取毫秒 tick */

    /* 启动阶段1 */
    s_channels[ch].state = MIDI_STATE_STAGE1;
    s_channels[ch].timer_ms = 0;
    start_stage1(ch);

    return 0;
}

/**
 * @brief 音符按下 - 7位精度版本 (兼容接口)
 */
int app_midi_note_on(uint8_t note, uint8_t velocity)
{
    /* 转换 7位 velocity 为 16位 */
    uint16_t velocity_16 = (uint16_t)velocity << 9;
    return app_midi_note_on_16(note, velocity_16);
}

/**
 * @brief 音符关闭
 */
int app_midi_note_off(uint8_t note) {
    /* 转换MIDI音符为通道号 */
    uint8_t ch = midi_parser_note_to_channel(note, s_board_id);
    if (ch >= MIDI_CH_COUNT)
    {
        return -1; /* 不属于本板 */
    }

    stop_channel(ch);
    return 0;
}

/**
 * @brief 全部音符关闭
 */
int app_midi_all_notes_off(void) {
    for (uint8_t i = 0; i < MIDI_CH_COUNT; i++)
    {
        stop_channel(i);
    }
    return 0;
}

/**
 * @brief 设置板号
 */
void app_midi_set_board_id(uint8_t board_id) {
    if (board_id >= 1 && board_id <= 11)
    {
        s_board_id = board_id;
    }
}

/**
 * @brief 处理控制变化命令（设定模式切换）
 */
int app_midi_process_cc(uint8_t cc_num, uint8_t cc_val)
{
    if (cc_num != 0x0E) return -1;

    extern user_config_t user_config;  /* 引用全局配置 */

    switch (cc_val)
    {
        case 0x01: /* 进入时间1设定模式 */
            user_config.setup_mode = 1;
            sys_manager_set_state(SYS_STATE_SETUP);
            break;

        case 0x02: /* 进入时间2设定模式 */
            user_config.setup_mode = 2;
            sys_manager_set_state(SYS_STATE_SETUP);
            break;

        case 0x03: /* 进入时间3-1占空比设定模式 */
            user_config.setup_mode = 3;
            sys_manager_set_state(SYS_STATE_SETUP);
            break;

        case 0x04: /* 进入时间3-2占空比设定模式 */
            user_config.setup_mode = 4;
            sys_manager_set_state(SYS_STATE_SETUP);
            break;

        case 0x7F: /* 保存并退出设定模式 */
            user_config.setup_mode = 0;
            sys_manager_set_state(SYS_STATE_PLAYING);
            /* TODO: 保存参数到 Flash (可选) */
            break;

        default:
            return -1;
    }

    return 0;
}

/* 私有函数实现 -------------------------------------------------------------*/

/**
 * @brief 处理状态机 (每1ms调用)
 */
static void process_state_machine(uint8_t ch) {
    channel_state_t *c = &s_channels[ch];
    uint32_t current_ms = HAL_GetTick();  /* 获取毫秒 tick */

    /* 检查7秒超时 */
    if ((current_ms - c->start_time_ms) >= MIDI_TIMEOUT_MS)
    {
        stop_channel(ch);
        return;
    }

    /* 状态机处理 */
    c->timer_ms++;

    switch (c->state)
    {
        case MIDI_STATE_STAGE1:
            /* 阶段1: 全功率启动 */
            if (c->timer_ms >= s_time1_ms)
            {
                c->state = MIDI_STATE_STAGE2_LOW;
                c->timer_ms = 0;
                start_stage2_low(ch);
            }
            break;

        case MIDI_STATE_STAGE2_LOW:
            /* 阶段2-低: 输出低电平 */
            if (c->timer_ms >= c->stage2_low_ms)
            {
                c->state = MIDI_STATE_STAGE2_HIGH;
                c->timer_ms = 0;
                start_stage2_high(ch);
            }
            break;

        case MIDI_STATE_STAGE2_HIGH:
            /* 阶段2-高: 输出高电平 */
            if (c->timer_ms >= c->stage2_high_ms)
            {
                c->state = MIDI_STATE_STAGE3_1;
                c->timer_ms = 0;
                start_stage3_1(ch);
            }
            break;

        case MIDI_STATE_STAGE3_1:
            /* 阶段3-1: 第一悬停 (100ms) */
            if (c->timer_ms >= MIDI_TIME3_1_DURATION_MS)
            {
                c->state = MIDI_STATE_STAGE3_2;
                c->timer_ms = 0;
                start_stage3_2(ch);
            }
            break;

        case MIDI_STATE_STAGE3_2:
            /* 阶段3-2: 第二悬停 (持续直到note off或超时) */
            /* 无需处理, 等待note off或7秒超时 */
            break;

        default:
            break;
    }
}

/**
 * @brief 启动阶段1: 全功率输出 (100%占空比)
 * @note 使用硬件最大精度 (2181) 代替传统 10000
 */
static void start_stage1(uint8_t ch)
{
#if MIDI2_INTERNAL_16BIT_VEL
    /* 高精度模式: 使用硬件全精度 */
    drv_pwm_start((pwm_channel_e)ch, PWM_DUTY_MAX_HIGHRES);
#else
    /* 传统模式: 使用 10000 (100.00%) */
    drv_pwm_start((pwm_channel_e)ch, PWM_DUTY_MAX);
#endif
}

/**
 * @brief 启动阶段2-低: 输出低电平
 * @note Stage 2 分为两个阶段：先低电平，后高电平
 *       总时长 = user_config.time2_ms (默认40ms)
 *       低电平时长比例 = (127 - velocity) / 127
 *       高电平时长比例 = velocity / 127
 */
static void start_stage2_low(uint8_t ch)
{
    channel_state_t *c = &s_channels[ch];
    extern user_config_t user_config;

    /* 获取7位velocity */
    uint8_t velocity_7 = c->velocity_16 >> 9;  /* 16位转7位 */

    /* 计算低电平和高电平的持续时间 */
    uint32_t total_ms = user_config.time2_ms;  /* 总时长（默认40ms）*/

    /* 低电平时长 = total_ms * (127 - velocity) / 127 */
    c->stage2_low_ms = (total_ms * (127 - velocity_7)) / 127;

    /* 高电平时长 = total_ms - 低电平时长 */
    c->stage2_high_ms = total_ms - c->stage2_low_ms;

    /* 输出0%占空比（低电平）*/
    drv_pwm_set_duty((pwm_channel_e)ch, 0);
}

/**
 * @brief 启动阶段2-高: 输出高电平
 */
static void start_stage2_high(uint8_t ch)
{
    /* 输出100%占空比（高电平）*/
#if MIDI2_INTERNAL_16BIT_VEL
    drv_pwm_set_duty((pwm_channel_e)ch, PWM_DUTY_MAX_HIGHRES);
#else
    drv_pwm_set_duty((pwm_channel_e)ch, PWM_DUTY_MAX);
#endif
}

/**
 * @brief 启动阶段3-1: 第一悬停 (板号特定26-35%占空比)
 */
static void start_stage3_1(uint8_t ch) {
    drv_pwm_set_duty((pwm_channel_e)ch, s_channels[ch].duty_1);
}

/**
 * @brief 启动阶段3-2: 第二悬停 (板号特定21-25%占空比)
 */
static void start_stage3_2(uint8_t ch) {
    drv_pwm_set_duty((pwm_channel_e)ch, s_channels[ch].duty_2);
}

/**
 * @brief 停止通道
 */
static void stop_channel(uint8_t ch) {
    drv_pwm_stop((pwm_channel_e)ch);
    s_channels[ch].state = MIDI_STATE_IDLE;
    s_channels[ch].timer_ms = 0;
    s_channels[ch].start_time_ms = 0;
}

/**
 * @brief 设定模式下处理 NOTE ON（用 velocity 调整参数）
 * @param velocity 7位力度值 (1-127)
 */
int app_midi_setup_adjust(uint8_t velocity)
{
    extern user_config_t user_config;

    if (velocity == 0 || velocity > 127) return -1;

    switch (user_config.setup_mode)
    {
        case 1: /* 时间1: velocity 1-127 直接映射到 1-127ms */
            user_config.time1_ms = velocity;
            break;

        case 2: /* 时间2: velocity 1-127 直接映射到 1-127ms */
            user_config.time2_ms = velocity;
            break;

        case 3: /* 时间3-1占空比: velocity 1-127 映射到 20-40% */
            user_config.time3_1_duty = 20 + (velocity * 20 / 127);
            break;

        case 4: /* 时间3-2占空比: velocity 1-127 映射到 16-30% */
            user_config.time3_2_duty = 16 + (velocity * 14 / 127);
            break;

        default:
            return -1;
    }

    return 0;
}

/******************************** 文件结束 *********************************/
